uniform float voxelSpacing;
uniform float sliceSpacing;
uniform sampler3D volume;

vec4 dataInterpolation( sampler3D data, const vec3 texCoords );
vec3 gradient( sampler3D data, const float scalarValue, const vec3 texCoord, const float voxelSpacing );
vec4 postClassification( const vec4 attributes, const vec3 grad );
float strengthVolume( const vec4 attributes, const vec3 grad );
vec4 lightIntensity( const vec3 grad );
vec4 volumeShader( const vec4 attributes, const float strength, const vec4 lightRadiance );
//
// This shader will take in several separate routines to calculate the:
//    1) scalar or multi-valued values
//    2) gradient 
//    3) a pseudo-coloring or post-processing of the values from 1.
//    4) a strength volume used to enhance material interfaces.
//    5) a routine to apply lighting calculations.
// Note, all of the routines except 1) can be null or simply return a default value.
//

void main() {
   // Look-up the data value(s) (upto four values)
   vec4 attributes = dataInterpolation( volume, gl_TexCoord[0].xyz );
   // Calculate the gradient for shading
   vec3 grad = gradient( volume, attributes.a, gl_TexCoord[0].xyz, voxelSpacing );
   // Apply a per-fragment color (data) transformation
   vec4 processedAttributes = postClassification( attributes, grad );
   // Determine the strength of any surface interfaces
   float strength = strengthVolume( processedAttributes, grad );
   // Calculate the lighting intensity
   vec4 lightRadiance = lightIntensity( grad );
   //
   // OK. Now we can combine everything together.
   //
   gl_FragColor = volumeShader( processedAttributes, strength, lightRadiance );
}


